import { RendererNode, VNode, h, onMounted, onUpdated, ref, render, watch } from "vue"
import { LoadingProps, useLoadingOption } from "./typing"
import wrapperStyle from "./style/wrapper"
import iconStyle from "./style/iconStyle"
import promptStyle from "./style/promptStyle"

/**
 * 封装Loading的hooks
 */
export const useLoading = (option?: useLoadingOption) => {

    // 如果用户传递的配置项,则合并默认配置项
    const defineOption: useLoadingOption = Object.assign({
        delay: 0,
        target: document.body,
        slot: LoadingIcon(),
        prompt: "别急,正加载呢"
    }, option ? option : {},)

    // 组件配置项
    const { delay, target, slot, prompt } = defineOption

    // Loading组件的实例
    let element = ref<RendererNode | null>()
    // 是否开启Loading
    const isLoading = ref<boolean>(false)
    /**
     * 显示Loading
     * @param delayTime 等待时间
     */
    const show = async (delayTime: number = delay!) => {
        if (delayTime && delayTime > 0) {
            await setTimeout(() => { }, delayTime);
        }
        isLoading.value = true
        renderComponent()
    }

    /**
     * 隐藏Loading
     * @param delayTime 等待时间
     */
    const hide = async (delayTime: number = delay!) => {
        if (delayTime && delayTime > 0) {
            await setTimeout(() => { }, delayTime);
        }
        isLoading.value = false
        renderComponent()
    }
    /**
     * 组件
     */
    const Loading = (props: Object & LoadingProps, ctx: any): VNode => {

        const { slots } = ctx
        const defaultProps = {
            style: {
                display: props.show ? "block" : "none",
                transition: "display 5s",
            },
            class: ["wrapper"],
            id: "xxx_wrapper",
        }

        return h("div", Object.assign(props, defaultProps), [
            h("div", {
                style: iconStyle()
            }, [
                slots?.default ? slots.default?.() : LoadingIcon(),
                slots?.prompt ? slots.prompt?.() : PromptText(),
            ])
        ])
    }
    /**
     * 渲染组件
     */
    const renderComponent = () => {

        let parentDom: Element;

        if (typeof target === "string") {
            const node = document.querySelector(target)
            if (!node) {
                throw new Error(`未查找到${target}元素`);
            }
            parentDom = node
        } else if (!target) {
            parentDom = document.body
        } else {
            parentDom = target as Element
        }

        const currentComponent = Loading({
            show: isLoading.value
        }, {
            slots: {
                default: () => slot ? h(slot) : LoadingIcon(),
                prompt: () => {
                    if (!prompt) return PromptText();
                    if (typeof prompt === "string") {
                        return PromptText();
                    } else {
                        return h(prompt)
                    }
                }
            }
        })
        element.value = currentComponent.el

        render(currentComponent, parentDom)
        return element.value
    }
    /**设置样式 */
    const setComponentStyle = () => {
        element.value = document.getElementById("xxx_wrapper")
        const wrapper = wrapperStyle(element.value!.parentNode as HTMLElement)
        for (const key in wrapper) {
            if (Object.prototype.hasOwnProperty.call(wrapper, key)) {
                const value = wrapper[key];
                element.value!.style[key] = value
            }
        }
    }

    setAnimation()

    onMounted(() => {
        renderComponent()
        if (!element.value) {
            setComponentStyle()
        }
    })
    onUpdated(() => {
    })

    return {
        show,
        hide,
        Loading
    }

}
/**
 * 创建一个提示语的Dom
 * @returns 
 */
const PromptText = (text: string = "正在加载,请稍候......"): VNode => {
    return h("div", {
        id: "xxx_loading_text",
        style: promptStyle()
    }, [text])
}
/**
* 创建一个Loading的图标
* @returns 返回一个Loading的图标
*/
const LoadingIcon = (): VNode => {
    return h("svg", {
        class: "icon",
        viewBox: "0 0 1024 1024",
        version: "1.1",
        xmlns: "http://www.w3.org/2000/svg",
        width: "3rem",
        height: "3rem",
        style: {

        }
    }, [h("path", {
        d: "M512 0a51.2 51.2 0 0 1 51.2 51.2v153.6a51.2 51.2 0 0 1-102.4 0V51.2a51.2 51.2 0 0 1 51.2-51.2z m0 768a51.2 51.2 0 0 1 51.2 51.2v153.6a51.2 51.2 0 0 1-102.4 0v-153.6a51.2 51.2 0 0 1 51.2-51.2z m512-256a51.2 51.2 0 0 1-51.2 51.2h-153.6a51.2 51.2 0 0 1 0-102.4h153.6a51.2 51.2 0 0 1 51.2 51.2zM256 512a51.2 51.2 0 0 1-51.2 51.2H51.2a51.2 51.2 0 0 1 0-102.4h153.6a51.2 51.2 0 0 1 51.2 51.2z m618.0352 362.0352a51.2 51.2 0 0 1-72.3968 0l-108.5952-108.5952a51.2 51.2 0 0 1 72.3968-72.3968l108.5952 108.544a51.2 51.2 0 0 1 0 72.448zM330.9568 330.9568a51.2 51.2 0 0 1-72.3968 0l-108.544-108.544a51.2 51.2 0 1 1 72.3968-72.448l108.544 108.5952a51.2 51.2 0 0 1 0 72.3968zM150.016 874.0352a51.2 51.2 0 0 1 0-72.3968l108.5952-108.5952a51.2 51.2 0 1 1 72.3968 72.3968l-108.544 108.5952a51.2 51.2 0 0 1-72.448 0zM693.0432 330.9568a51.2 51.2 0 0 1 0-72.3968l108.544-108.5952a51.2 51.2 0 0 1 72.448 72.3968L765.44 330.9568a51.2 51.2 0 0 1-72.3968 0z",
        fill: "#fff"
    })])
}
/**
 *  动态添加style标签
 */
const setAnimation = () => {
    let style = document.createElement("style")
    style.type = "text/css"
    style.innerHTML = `
        @keyframes loadingAnimation {
            0% {
              transform:  rotate(0turn);
            }
            100% {
              transform:  rotate(1turn);
            }
          }
          
          @keyframes flashing {
            0% {
                opacity:0.3;
            }
            50% {
                opacity:1;
            }
             100% {
                opacity:0.3;
            }
          }
          #xxx_wrapper svg {
            animation: loadingAnimation 1s infinite;
          }
          #xxx_loading_text {
            white-space: nowrap;
            animation: flashing 5s ease-in infinite;
            overflow: hidden;
          }
          
    `
    document.getElementsByTagName("head").item(0)?.appendChild(style)
}